#include <stdio.h>
#include "OpenCLTestingProcessor.h"


#pragma mark INITIALIZE 

OpenCLTestingProcessor::OpenCLTestingProcessor(): OpenCLProcessorBase("simply_kernels.cl") {
    createKernels();
}

OpenCLTestingProcessor::~OpenCLTestingProcessor() {
    
    clReleaseMemObject(inBuffer_);
    clReleaseMemObject(outBuffer_);
    clFlush(cmdQueue_);
    
    delete [] data_;
}

void OpenCLTestingProcessor::createKernels() {
    inOutKernel_ = clCreateKernel(program_, "in_out", &lastCommandStatus_);
}



#pragma mark BUFFERS

void OpenCLTestingProcessor::setBuffers(unsigned int size) {
    if(size == 0)
        throw WrongFunArgVal_Exception();
    
    if(size == buffersLength_)
        return;
    
    if(buffersLength_ != 0) {
        delete [] data_;
        clReleaseMemObject(inBuffer_);
        clReleaseMemObject(outBuffer_);
    }
    
    data_ = new float[size];
    for(int i = 0; i < size; ++i)
        data_[i] = 1;
    
    inBuffer_ = clCreateBuffer(
                               context_,
                               CL_MEM_READ_WRITE,
                               size * sizeof(float),
                               NULL,
                               &lastCommandStatus_);
    outBuffer_ = clCreateBuffer(
                               context_,
                               CL_MEM_READ_WRITE,
                               size * sizeof(float),
                               NULL,
                               &lastCommandStatus_);
    
    lastCommandStatus_ = clEnqueueWriteBuffer(
                                  cmdQueue_,
                                  inBuffer_,
                                  CL_FALSE,
                                  0,
                                  size * sizeof(float),
                                  data_,
                                  0,
                                  NULL,
                                  NULL);
    
    
    lastCommandStatus_  = clSetKernelArg(
                             inOutKernel_,
                             0,
                             sizeof(cl_mem),
                             &inBuffer_);
	
	lastCommandStatus_ |= clSetKernelArg(
                             inOutKernel_,
                             1,
                             sizeof(cl_mem),
                             &outBuffer_ );
    
    buffersLength_ = size;
    clFlush(cmdQueue_);
}

void OpenCLTestingProcessor::setDataValue(float value) {
    for(int i = 0; i < buffersLength_; ++i)
        data_[i] = value;
}



#pragma mark TRANSFER 

void OpenCLTestingProcessor::transferDataToGPU() {
    cl_int lastCommandStatus_;
    lastCommandStatus_ = clEnqueueWriteBuffer(
                                  cmdQueue_,
                                  inBuffer_,
                                  CL_FALSE,
                                  0,
                                  buffersLength_ * sizeof(float),
                                  data_,
                                  0,
                                  NULL,
                                  NULL);
}

void OpenCLTestingProcessor::transferDataFromGPU(float* destiny) {
    cl_int lastCommandStatus_;
    lastCommandStatus_ = clEnqueueReadBuffer(
                                  cmdQueue_,
                                  outBuffer_,
                                  CL_FALSE,
                                  0,
                                  buffersLength_ * sizeof(float),
                                  destiny,
                                  0,
                                  NULL,
                                  NULL);
}

void OpenCLTestingProcessor::executeTheSimplestKernel() {
	size_t globalWorkSize[1];
	globalWorkSize[0] = buffersLength_;

    lastCommandStatus_ = clEnqueueNDRangeKernel(
                                    cmdQueue_,
                                    inOutKernel_,
                                    1,
                                    NULL,
                                    globalWorkSize,
                                    NULL,
                                    0,
                                    NULL,
                                    NULL);

}